package com.ktwlsoft.archivemanage.domain.business.businessService;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.*;

import com.ktwlsoft.archivemanage.config.FileStorageProperties;
import com.ktwlsoft.archivemanage.payload.TemFileResult;
import com.ktwlsoft.archivemanage.payload.exception.BusinessException;
import com.ktwlsoft.archivemanage.payload.exception.FileStorageException;
import com.ktwlsoft.archivemanage.payload.exception.MyFileNotFoundException;

import com.ktwlsoft.archivemanage.service.utils.StringUtil;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

@Service
public class FileService {

    private final FileStorageProperties fileStorageProperties;

    public FileService(FileStorageProperties fileStorageProperties) {
        this.fileStorageProperties = fileStorageProperties;
    }

    /**
     * Store file pieces until the last piece arrived and merge all pieces to one file.
     * @param file file piece or file
     * @param fileName origin file name
     * @param sliceNum the file piece number
     * @param isLast indicate whether is the last piece.
     * @param targetPathStr target storing location of the merged file, it is a relative url.
     * @return state of the processing of store file piece.
     */
    public TemFileResult storeFileBySlice(MultipartFile file, String fileName, int sliceNum, Boolean isLast,
                                          String targetPathStr) {
        try {
            Path temPath = Paths.get(fileStorageProperties.getTemDir()).toAbsolutePath().normalize();
            Path targetPath = Paths.get(targetPathStr).toAbsolutePath().normalize();

            Files.createDirectories(temPath);
            Files.createDirectories(targetPath);

            if (fileName.contains("..")) {
                throw new FileStorageException("抱歉! 文件包含不合法的路径序列:" + fileName);
            }
            // Normalize file name
            String temFileName = fileName + sliceNum + ".tem";
            Path targetLocation = temPath.resolve(temFileName);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
            StringBuilder fileUrl = new StringBuilder();
            if (isLast) {
                fileUrl.append(this.mergeTem(fileStorageProperties.getTemDir(), targetPathStr, fileName, sliceNum));
            }
            return new TemFileResult(isLast, fileUrl.toString(), fileName);
        } catch (Exception e) {
            for (long i = 0; i <= sliceNum; i++) {
                Path filePath = Paths.get(fileStorageProperties.getTemDir() + fileName + i + ".tem").toAbsolutePath();
                File temFile = new File(filePath.toString());
                temFile.delete();
            }
            return new TemFileResult(e.getMessage());
        }
    }

    public String storeFile(MultipartFile file, String dir) throws IOException {
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        Path storePath = Paths.get(dir +"/"+ file.getOriginalFilename()).toAbsolutePath().normalize();
        try{
            Files.createDirectories(storePath);
        }catch (FileAlreadyExistsException e){
            // do nothing, if the directory exist..
        }
        try {
            // Check if the file's name contains invalid characters
            if (fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
            }
            // Copy file to the target location (Replacing existing file with the same name)
            //Path targetLocation = storePath.resolve(fileName);
            Files.copy(file.getInputStream(), storePath, StandardCopyOption.REPLACE_EXISTING);
            return Paths.get(dir + "/" + fileName).normalize().toString();
        } catch (IOException ex) {
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }

    public Resource loadFileAsResource(String fileName, String relatePath) {
        try {
            Path fileStorageLocation = Paths.get(relatePath).toAbsolutePath().normalize();
            Path filePath = fileStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if (resource.exists()) {
                return resource;
            } else {
                throw new MyFileNotFoundException("文件未找到" + fileName);
            }
        } catch (MalformedURLException ex) {
            throw new MyFileNotFoundException("文件未找到" + fileName, ex);
        }
    }

    public String mergeTem(String temFilePathStr, String targetPathStr, String fileName, int sliceNum) throws Exception {
        Path targetPath = Paths.get(targetPathStr + "/" + fileName).toAbsolutePath().normalize();
        Path temFilePath = Paths.get(temFilePathStr).toAbsolutePath().normalize();
        try (FileOutputStream fileOutputStream = new FileOutputStream(targetPath.toString())) {
            byte[] buff = new byte[1024];
            for (long i = 0; i <= sliceNum; i++) {
                String pieceFile = fileName + i + ".tem";
                Path fileLocation = temFilePath.resolve(pieceFile);
                File file = new File(fileLocation.toString());
                InputStream inputStream = new FileInputStream(file);
                int len = 0;
                while ((len = inputStream.read(buff)) != -1) {
                    fileOutputStream.write(buff, 0, len);
                }
                inputStream.close();
                file.delete();
            }
        } catch (Exception e) {
            for (long i = 0; i <= sliceNum; i++) {
                String pieceFile = fileName + i + ".tem";
                Path fileLocation = Paths.get(temFilePathStr + "/" + pieceFile).toAbsolutePath();
                File file = new File(fileLocation.toString());
                file.delete();
            }
            throw new BusinessException("合并文件失败:" + e.getMessage());
        }
        return targetPathStr + "/" + fileName;
    }
}
